/*
 * $Id: LocationImportHelper.java 42 2013-04-17 15:33:59Z gabakyan $
 * $Author: gabakyan $
 * $Revision: 42 $
 * $Date: 2013-04-17 15:33:59 +0000 (Wed, 17 Apr 2013) $
 *
 * Copyright (c) 2013 Supply Chain Intelligence (SCI), Inc.
 * http://www.scintelligence.com/, Email: info@scintelligence.com
 * All rights reserved.
 *
 * This file is part of Logistics Map.
 *
 * Logistics Map is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, version 3 of the License.
 *
 * Logistics Map is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Logistics Map.  If not, see <http://www.gnu.org/licenses/>.
 */

package com.sci.logisticsmap.service.support;

import com.sci.logisticsmap.service.GeodataService;
import com.sci.logisticsmap.service.model.GeodataResponse;
import com.sci.logisticsmap.support.LocationImportSupportedMimeType;
import com.sci.logisticsmap.support.Utilities;
import com.sci.logisticsmap.service.model.SessionUserDTModel;
import com.sci.logisticsmap.support.model.ResponseWrapper;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileItemFactory;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.io.InputStream;
import java.util.List;

/**
 * The utility class which provides helper methods for importing the Locations.
 *
 * @author gabakyan@gmail.com (Last modified by $Author: gabakyan $)
 * @version $Revision: 42 $
 */
@Component
public final class LocationImportHelper {
    /**
     * The logger.
     */
    private static final Logger logger = LoggerFactory.getLogger(LocationImportHelper.class);

    /**
     * The <code>multipart/form-data</code> content type.
     */
    private static final String CONTENT_TYPE_MULTIPART_FORM_DATA = "multipart/form-data";
    /**
     * The <code>application/octet-stream</code> content type.
     */
    private static final String CONTENT_TYPE_APPLICATION_OCTET_STREAM = "application/octet-stream";

    /**
     * The <code>X-Mime-Type</code> header.
     */
    private static final String HEADER_X_MIME_TYPE = "X-Mime-Type";
    /**
     * The <code>X-File-Name</code> header.
     */
    private static final String HEADER_X_FILE_NAME = "X-File-Name";

    /**
     * The geodata service.
     */
    @Autowired
    private GeodataService geodataService;

    /**
     * Imports Locations.
     *
     * @param sessionUser The session user.
     * @param request The http servlet request.
     *
     * @return The Geodata wrapped response.
     */
    public ResponseWrapper<GeodataResponse> importLocations(SessionUserDTModel sessionUser, HttpServletRequest request) {
        try {
            String mimeType = null;
            InputStream inputStream = null;
            boolean supportedRequestContentType = false;
            if (request.getContentType() != null) {
                logger.debug("importLocations: content type = {}", request.getContentType());
                // for uploading files using form and iframe
                if (request.getContentType().startsWith(CONTENT_TYPE_MULTIPART_FORM_DATA)) {
                    FileItemFactory factory = new DiskFileItemFactory();
                    ServletFileUpload upload = new ServletFileUpload(factory);

                    List fileItems = upload.parseRequest(request);
                    logger.debug("importLocations: files count = {}", fileItems.size());
                    for (int i = 0; i < fileItems.size(); i++) {
                        FileItem fileItem = (FileItem) fileItems.get(i);
                        if (!fileItem.isFormField()) {
                            mimeType = fileItem.getContentType();
                            inputStream = fileItem.getInputStream();
                            logger.debug("importLocations: file content type = {}", fileItems.size());
                            break;
                        }
                    }
                    supportedRequestContentType = true;
                // for uploading files using XHR
                } else if (request.getContentType().startsWith(CONTENT_TYPE_APPLICATION_OCTET_STREAM)) {
                    if (StringUtils.isNotBlank(request.getHeader(HEADER_X_MIME_TYPE))) {
                        mimeType = request.getHeader(HEADER_X_MIME_TYPE);
                        inputStream = request.getInputStream();
                        logger.debug("importLocations: X-Mime-Type = {}", mimeType);
                    // workaround for Chrome old versions (< 24 (~20))
                    } else if (StringUtils.isNotBlank(request.getHeader(HEADER_X_FILE_NAME))) {
                        String xFilename = request.getHeader(HEADER_X_FILE_NAME);
                        String fileExtension = Utilities.getFileExtension(xFilename);
                        if (StringUtils.isNotBlank(fileExtension)) {
                            if (fileExtension.equalsIgnoreCase("txt")) {
                                mimeType = LocationImportSupportedMimeType.TEXT_PLAIN;
                            } else if (fileExtension.equalsIgnoreCase("csv")) {
                                mimeType = LocationImportSupportedMimeType.TEXT_COMMA_SEPARATED_VALUES;
                            }
                        }
                        inputStream = request.getInputStream();
                        logger.debug("importLocations: X-File-Name = {}, fileExtension = {}, mimeType = {}", xFilename, fileExtension, mimeType);
                    }
                    supportedRequestContentType = true;
                }
            }
            logger.debug("importLocations: mimeType = {}, supportedRequestContentType = {}", mimeType, supportedRequestContentType);

            if (supportedRequestContentType) {
                if (mimeType != null) {
                    //if (request.getParameter("locationImportTemplateId") != null && request.getParameter("locationImportTemplateId").trim().length() > 0) {
                        if (LocationImportUtilities.isSupportedLocationImportMimeType(mimeType)) {
                            //ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
                            //IOUtils.copy(inputStream, outputStream, Constants.DEFAULT_ENCODING);

                            HttpSession session = request.getSession();
                            //String locationImportTemplateId = request.getParameter("locationImportTemplateId");
                            return geodataService.importLocations(sessionUser, session.getId()/*, locationImportTemplateId*/, mimeType, inputStream/*outputStream.toByteArray()*/);
                        } else {
                            StringBuilder stringBuilder = new StringBuilder();
                            throw new IllegalStateException(stringBuilder.append("Unsupported MIME Type \"").append(mimeType).append("\". Valid extension(s): txt, csv.").toString());
                        }
                    /*} else {
                        throw new IllegalStateException("Template Id is required");
                    }*/
                } else {
                    throw new IllegalStateException("MIME Type is required. Valid extension(s): txt, csv.");
                }
            } else {
                throw new IllegalStateException("Unsupported content type of request");
            }
        } catch (ServiceException e) {
            throw e;
		} catch (Exception e) {
            logger.error("Error encountered while processing the request", e);
            throw new ServiceException(e);
        }
    }
}
